#include <cassert>

#include <math.h>

class TPoint;
class TVector;

class TSpace {
private:
	double x;
	double y;
	double z;

protected:
	bool Equal(const TSpace &right) const {
		double x, y, z;
		right.GetAll(x, y, z);

		return (this->x == x && this->y == y && this->z == z);
	}

	bool NotEqual(const TSpace &right) const {
		double x, y, z;
		right.GetAll(x, y, z);

		return !(this->x == x && this->y == y && this->z == z);
	}

	void Copy(const TSpace &right) {
		double x, y, z;

		right.GetAll(x, y, z);
		this->SetAll(x, y, z);
	}

	TSpace Add(const TSpace &right) const {
		double x, y, z;

		right.GetAll(x, y, z);
		TSpace ret(this->x + x, this->y + y, this->z + z);

		return ret;
	}

	TSpace AddWith(const TSpace &right) {
		double x, y, z;
		right.GetAll(x, y, z);

		this->x += x;
		this->y += y;
		this->z += z;

		return *this;
	}

	TSpace Sub (const TSpace &right) const {
		double x, y, z;

		right.GetAll(x, y, z);
		TSpace ret(this->x - x, this->y - y, this->z - z);

		return ret;
	}

	TSpace SubWith(const TSpace &right) {
		double x, y, z;
		right.GetAll(x, y, z);

		this->x -= x;
		this->y -= y;
		this->z -= z;

		return *this;
	}
	
	TSpace Scale(double factor) const {
		double x, y, z;
		this->GetAll(x, y, z);
		TSpace ret(x*factor, y*factor, z*factor);

		return ret;
	}

	TSpace ScaleWith(double factor) {
		double x, y, z;
		this->GetAll(x, y, z);
		this->SetAll(x*factor, y*factor, z*factor);

		return *this;
	}

public:
	TSpace(double x, double y, double z) {
		SetAll(x, y, z);
	}
	
	TSpace() {
		SetAll(0.0, 0.0, 0.0);
	}

	TSpace(const TSpace &original) {
		double x, y, z;
		original.GetAll(x, y, z);
		SetAll(x, y, z);
	}

	void SetX(double x) { this->x = x; }
	void SetY(double y) { this->y = y; }
	void SetZ(double z) { this->z = z; }
	void SetAll(double x, double y, double z) {
		this->x = x;
		this->y = y;
		this->z = z;
	}

	double GetX() const { return this->x; }
	double GetY() const { return this->y; }
	double GetZ() const { return this->z; }
	void GetAll(double &x, double &y, double &z) const {
		x = this->x;
		y = this->y;
		z = this->z;
	}

	TSpace operator= (const TSpace &right) {
		this->Copy(right);
		return *this;
	}

	bool operator== (const TSpace &right) const { return this->Equal(right); }
	bool operator!= (const TSpace &right) const { return this->NotEqual(right); }
	TSpace operator+ (const TSpace &right) const { return this->Add(right); }
	TSpace operator- (const TSpace &right) const { return this->Sub(right); }
	friend TSpace operator* (TSpace &left, double right)	{ return left.Scale(right); }
	friend TSpace operator* (double left, TSpace &right) { return right.Scale(left); }
};

class TVector : protected TSpace {
private:
	double scalar;

	void UpdateScalar() {
		double x, y, z;
		this->GetAll(x, y, z);

		this->scalar = sqrt(x*x + y*y + z*z);
	}

protected:
	void Copy(const TVector &right) {
		TSpace::Copy(right);
		UpdateScalar();
	}

	bool Equal(const TVector &right) const {
		return TSpace::Equal(right);
	}

	bool NotEqual(const TVector &right) const {
		return TSpace::NotEqual(right);
	}

	TVector ScaleWith(const double &right) {
		TSpace::ScaleWith(right);
		UpdateScalar();
	}

	TVector Scale(const double &factor) const {
		TVector ret(*this);
		ret.ScaleWith(factor);

		return ret;
	}

	TVector AddWith(const TVector &right) {
		TSpace::AddWith(right);
		UpdateScalar();
		return *this;
	}

	TVector Add(const TVector &right) const {
		TVector ret(*this);
		ret.AddWith(right);

		return ret;
	}

	TVector SubWith(const TVector &right) {
		TSpace::SubWith(right);
		UpdateScalar();
		return *this;
	}

	TVector Sub(const TVector &right) const {
		TVector ret(*this);
		ret.SubWith(right);

		return ret;
	}

public:
	TVector(double x, double y, double z) {
		this->SetAll(x, y, z);
		UpdateScalar();
	}

	TVector() {
		this->SetAll(0.0, 0.0, 0.0);
		this->scalar = 0.0;
	}

	TVector(const TVector &original) {
		double x, y, z;
		original.GetAll(x, y, z);
		this->SetAll(x, y, z);
		UpdateScalar();
	}

	double GetScalar() const { return this->scalar; }

	TVector operator= (TVector right) {
		this->Copy(right);
		return *this;
	}

	TVector operator*= (const double &right) { return this->ScaleWith(right); }
	TVector operator+= (const TVector &right) { return this->AddWith(right); }
	TVector operator-= (const TVector &right) { return this->SubWith(right); }
	TVector operator+ (const TVector &right) const { return this->Add(right); }
	TVector operator- (const TVector &right) const { return this->Sub(right); }
	friend TVector operator* (TVector &left, const double &right) { return left.Scale(right); }
	friend TVector operator* (const double &left, TVector &right) { return right.Scale(left); }

	bool operator== (const TVector &right) const { return (this->Equal(right)); }
	bool operator!= (const TVector &right) const { return (this->NotEqual(right)); }
	bool operator> (const TVector &right) const { return this->GetScalar() > right.GetScalar(); }
	bool operator< (const TVector &right) const { return this->GetScalar() < right.GetScalar(); }
	bool operator>= (const TVector &right) const { return this->GetScalar() >= right.GetScalar(); }
	bool operator<= (const TVector &right) const { return this->GetScalar() <= right.GetScalar(); }
};

class TPoint : protected TSpace {
protected:
	TPoint AddWith(const TVector &vec) {
		TSpace::AddWith(vec);
		return *this;
	}

	TPoint Add(const TVector &vec) const {
		TPoint p(*this);
		p.AddWith(vec);

		return p;
	}

	TPoint SubWith(const TVector &vec) {
		TSpace::SubWith(vec);
		return *this;
	}

	TPoint Sub(const TVector &vec) const {
		TPoint p(*this);
		p.SubWith(vec);

		return p;
	}
public:
	TPoint(double x, double y, double z) {
		SetAll(x, y, z);
	}
	
	TPoint() {
		SetAll(0.0, 0.0, 0.0);
	}

	TPoint(const TPoint &original) {
		double x, y, z;
		original.GetAll(x, y, z);
		SetAll(x, y, z);
	}

	TPoint operator= (const TPoint &right) {
		this->Copy(right);
		return *this;
	}

	TPoint operator+= (const TVector &vec) { return this->AddWith(vec); }
	TPoint operator-= (const TVector &vec) { return this->SubWith(vec); }
	bool operator!= (const TPoint &right) const { return this->NotEqual(right); }
	bool operator== (const TPoint &right) const { return this->Equal(right); }
	friend TPoint operator+ (TPoint &point, const TVector &vec) { return point.Add(vec); }
	friend TPoint operator+ (const TVector &vec, TPoint &point) { return point.Add(vec); }
	TPoint operator- (const TVector &right) const { return this->Sub(right); }

};

int main() {
	TPoint p(7, 8, 6);
	TVector v(3, 5, 8);
	TPoint r;
	TPoint t(7, 8, 6);

	r = p - v;

	assert(p == t);

	return 0;
}
